#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <unistd.h> // 用于 sleep 函数 
#define PORT 8080
#define header_size 100

// 定义一个结构来保存HTML文件的内容
typedef struct Resource
{
    char *data;  // 存储HTML内容的字符串
    size_t size; // 字符串的大小
} Resource;

// 定义一个结构来保存请求信息
typedef struct ResponseHeader
{
    char *Body;         // 存储完整的响应表头信息
    int Content_Length; // 数据长度(Resource)
    char *Content_Type; // 内容类型
    char *Charset;      // 编码格式
    char *Status_Code;  // 状态码

} ResponseHeader;

// 拼接响应标头
void concatResponseHeader(ResponseHeader *r, Resource *res)
{
    r->Content_Length = res->size;
    sprintf(r->Body, "HTTP/1.1 %s\nContent-Type: %s; charset=%s\nContent-Length: %d\n\n", r->Status_Code, r->Content_Type, r->Charset, r->Content_Length);
    return;
}

Resource *readHTMLFile(const char *filename)
{
    Resource *htmlFile = (Resource *)malloc(sizeof(Resource));

    FILE *file = fopen(filename, "r");
    if (file == NULL)
    {
        printf("Error:无法打开文件\n");
        return NULL;
    }

    fseek(file, 0, SEEK_END);
    long file_size = ftell(file);
    fseek(file, 0, SEEK_SET);

    // 分配内存来存储文件数据
    htmlFile->data = (char *)malloc(file_size);
    if (!htmlFile->data)
    {
        printf("内存分配失败！");
        return NULL;
    }

    fread(htmlFile->data, 1, file_size, file);
    htmlFile->data[file_size] = '\0';
    htmlFile->size = file_size;

    fclose(file);

    return htmlFile;
}

Resource *readBinary(const char *filename)
{
    Resource *myfile = (Resource *)malloc(sizeof(Resource)); // 初始化 Resource 结构体

    // 读取并发送图标文件数据
    FILE *icon_file = fopen(filename, "rb");
    if (!icon_file)
    {
        printf("文件打开失败！");
        return NULL;
    }

    fseek(icon_file, 0, SEEK_END);
    long file_size = ftell(icon_file);
    myfile->size = file_size;
    fseek(icon_file, 0, SEEK_SET);

    // 分配内存来存储文件数据
    myfile->data = (char *)malloc(file_size);
    if (!myfile->data)
    {
        printf("内存分配失败！");
        return NULL;
    }

    // 读取文件数据
    fread(myfile->data, 1, file_size, icon_file);
    fclose(icon_file);
    return myfile;
}

// 解析HTTP请求中的URL
char *parseURL(char *request)
{
    printf("客户端请求:\n");
    printf("--------------------\n");
    printf("%s\n", request);
    printf("--------------------\n");

    char *start = strstr(request, "GET ");
    if (start == NULL)
    {
        printf("无法匹配的url前缀。\n");
        return NULL;
    }

    start += 4; // 跳过 "GET "
    char *end = strstr(start, " ");
    if (end == NULL)
    {
        printf("无法匹配的url后缀。\n");
        return NULL;
    }

    // 提取URL并返回
    int url_length = end - start;
    char *url = (char *)malloc(url_length + 1);
    strncpy(url, start, url_length);
    url[url_length] = '\0';

    return url;
}

int main(int argc, char const *argv[])
{
    /*
        cd /usr/local/man/http_load-12mar2006
        ./http_load -rate 1 -seconds 5 http://localhost:8080


        http_load -parallel 5 -seconds 10 http://localhost:8080/favicon.ico
        ./http_load -parallel 5 -seconds 10 http://www.baidu.com/ 

        测试网站
        http://localhost:8080/
        http://localhost:8080/favicon.ico
        http://localhost:8080/1
        https://www.baidu.com/
    */

    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    // 读取index界面
    Resource *page_index = readHTMLFile("index.html");
    // 读取404页面
    Resource *page_404 = readHTMLFile("404.html");
    // 读取图标文件
    Resource *page_icon = readHTMLFile("favicon.ico");

    // 初始化响应头
    ResponseHeader *response_header = (ResponseHeader *)malloc(sizeof(ResponseHeader));
    response_header->Charset = (char *)malloc(sizeof(char) * 20);
    response_header->Content_Length = 0;
    response_header->Content_Type = (char *)malloc(sizeof(char) * 50);
    response_header->Body = (char *)malloc(sizeof(char) * 200);
    response_header->Status_Code = (char *)malloc(sizeof(char) * 10);

    // 创建socket文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        perror("Error:socket failed");
        exit(EXIT_FAILURE);
    }
    // 设置地址结构体
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // 绑定socket文件描述符到本地地址上
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
    {
        perror("Error:bind failed");
        exit(EXIT_FAILURE);
    }
    // 监听端口，等待客户端连接
    if (listen(server_fd, 3) < 0)
    {
        perror("Error:listen failed");
        printf("Error:listen failed");
        exit(EXIT_FAILURE);
    }
    printf("Server started on port %d\n", PORT);

    while (1)
    {
        sleep(1); // 暂停一秒  

        // 接受客户端连接并创建新socket文件描述符
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0)
        {
            perror("Error:accept failed");
            printf("Error:accept failed");
            exit(EXIT_FAILURE);
        }
        // 从客户端读取请求内容并存储到buffer中
        read(new_socket, buffer, 1024);
        printf("Received: %s\n", buffer);

        // 解析HTTP请求，获取请求的URL
        char *url = parseURL(buffer);
        printf("解析请求url为:%s\n", url);

        // 根据URL来处理不同的路由
        if (strcmp(url, "/") == 0)
        {
            // 编写请求头
            strcpy(response_header->Charset, "UTF-8");
            strcpy(response_header->Content_Type, "text/html");
            strcpy(response_header->Status_Code, "200 OK");
            concatResponseHeader(response_header, page_index);
            // 写入请求头
            write(new_socket, response_header->Body, strlen(response_header->Body));
            // 向浏览器写入数据
            write(new_socket, page_index->data, page_index->size);
        }
        else if (strcmp(url, "/other_route") == 0)
        {
        }
        else if (strcmp(url, "/favicon.ico") == 0)
        {
            // 编写请求头
            strcpy(response_header->Charset, "UTF-8");
            strcpy(response_header->Content_Type, "image/png");
            strcpy(response_header->Status_Code, "200 OK");
            concatResponseHeader(response_header, page_icon);
            // 写入请求头
            write(new_socket, response_header->Body, strlen(response_header->Body));
            // 向浏览器写入图片数据
            write(new_socket, page_icon->data, page_icon->size);

        }
        else // 处理未知路由的响应
        {
            printf("访问了未知页面...\n");

            // 编写请求头
            strcpy(response_header->Charset, "UTF-8");
            strcpy(response_header->Content_Type, "text/html");
            strcpy(response_header->Status_Code, "404 Not Found");
            concatResponseHeader(response_header, page_404);

            // 向浏览器写入请求头
            write(new_socket, response_header->Body, strlen(response_header->Body));

            // 向浏览器写入数据
            write(new_socket, page_404->data, page_404->size);
        }
        // 释放url地址
        free(url);
        printf("Response sent\n");

        // 关闭新socket文件描述符
        close(new_socket);
    }

    // 释放内存
    free(page_index->data);
    free(page_index);

    // 释放内存
    free(page_icon->data);
    free(page_icon);

    return 0;
}
